package com.example.guessthesoundtrack;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Locale;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceView;

public class GameView extends SurfaceView {
	public static float HEIGHT = 0f;
	public static float WIDTH = 0f;
	
	private ArrayList<Letter> letters;
	private ArrayList<Shadow> shadows;
	private ArrayList<Sprite> buttons;
	private ArrayList<Sprite> sprites;
	private ArrayList<Dialog> dialogs;
	private ArrayList<Level> levels;
	
	private SharedPreferences preferences;
	private BitmapDrawable background;
	private Activity activity;
	private Bitmap letter_clicked, letter_unclicked, shadow_normal, shadow_highlighted, coin_clicked, coin_unclicked, help_clicked, help_unclicked, play, dialog_clicked, dialog_unclicked;
	private Paint paint;
	private Rect rect, bounds;
	
	private Sprite clicked;
	
	private String movie;
	
	private char[] alphabet = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
	
	private long time;
	private float dx, dy;
	private int level;

	public GameView(Context context) {
		super(context);
		activity = (Activity) context;
	}
	
	public GameView(Context context, AttributeSet attrs) {
		super(context, attrs);
		activity = (Activity) context;
	}
	
	public GameView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		activity = (Activity) context;
	}
	
	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		setWillNotDraw(false);
		
		preferences = activity.getSharedPreferences("GuessTheSoundtrack", Activity.MODE_PRIVATE);
		level = preferences.getInt("level", 0);
		
		rect = new Rect();
		bounds = new Rect();
		
		paint = new Paint();
		paint.setAlpha(128);
		paint.setTextSize(48f);
		paint.setTextAlign(Align.CENTER);
		paint.setTypeface(Typeface.DEFAULT_BOLD);
		
		dx = 0f;
		dy = 0f;
		
		try {
			InputStream in = activity.getAssets().open("levels.xml");
			XmlPullParser parser = XmlParser.toXmlParser(in);
			levels = XmlParser.getLevels(parser);
		} catch (IOException e) {
			Log.e("Guess", e.toString());
		} catch (XmlPullParserException e) {
			Log.e("Guess", e.toString());
		}

		// Getting the screen specs
		DisplayMetrics metrics = new DisplayMetrics();
		activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
		HEIGHT = metrics.heightPixels;
		WIDTH = metrics.widthPixels;
		
		// Creating background
		background = new BitmapDrawable(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.tile));
		background.setBounds(0, 0, (int)WIDTH, (int)HEIGHT);
		background.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);

		// Creating bitmaps
		letter_clicked = BitmapFactory.decodeResource(getResources(), R.drawable.letter_clicked);
		letter_unclicked = BitmapFactory.decodeResource(getResources(), R.drawable.letter_unclicked);
		shadow_normal = BitmapFactory.decodeResource(getResources(), R.drawable.shadow);
		shadow_highlighted = BitmapFactory.decodeResource(getResources(), R.drawable.shadow_highlighted);
		dialog_clicked = BitmapFactory.decodeResource(getResources(), R.drawable.dialog_clicked);
		dialog_unclicked = BitmapFactory.decodeResource(getResources(), R.drawable.dialog_unclicked);
		coin_clicked = BitmapFactory.decodeResource(getResources(), R.drawable.coins_clicked);
		coin_unclicked = BitmapFactory.decodeResource(getResources(), R.drawable.coins_unclicked);
		help_clicked = BitmapFactory.decodeResource(getResources(), R.drawable.help_clicked);
		help_unclicked = BitmapFactory.decodeResource(getResources(), R.drawable.help_unclicked);
		play = BitmapFactory.decodeResource(getResources(), R.drawable.play);
		
		// Creating sprites
		letters = new ArrayList<Letter>();
		shadows = new ArrayList<Shadow>();
		buttons = new ArrayList<Sprite>();
		sprites = new ArrayList<Sprite>();
		dialogs = new ArrayList<Dialog>();
		prepare();
		
		//time = GregorianCalendar.getInstance().getTimeInMillis();
	}
	 
	@Override
	protected void onDraw(Canvas canvas) {
		// Update
		int delta = (int)(GregorianCalendar.getInstance().getTimeInMillis() - time);
		for (int i = 0; i < sprites.size(); i++)
			sprites.get(i).update(delta);
		time = GregorianCalendar.getInstance().getTimeInMillis();
		
		// Draw background
		background.draw(canvas);
	
		// Draw buttons
		for (int i = 0; i < buttons.size(); i++)
			buttons.get(i).draw(canvas);
		
		// Draw shadows
		for (int i = 0; i < shadows.size(); i++)
			shadows.get(i).draw(canvas);
		
		// Draw letters
		for (int i = 0; i < letters.size(); i++)
			letters.get(i).draw(canvas);
		
		// Draw dialogs
		for (int i = 0; i < dialogs.size(); i++)
			dialogs.get(i).draw(canvas);
		
		// Draw letter on shadow if colliding, else draw dragging shadow
		if (clicked instanceof Letter) {
			Letter l = (Letter)clicked;
			int j = 0;
			boolean found = false;
			while (!found && j < shadows.size()) {
				if (shadows.get(j).isColliding(dx, dy))
					found = true;
				else
					j++;
			}
			if (found) {
				Shadow s = shadows.get(j);
				s.getPaint().getTextBounds("" + l.getLetter(), 0, 1, s.getBounds());
				canvas.drawBitmap(clicked.getUnclicked(), null, s.getRect(), null);
				canvas.drawText("" + l.getLetter(), s.getX() + (s.getWidth() / 2f), s.getY() + (s.getHeight() / 2f) + (s.getBounds().height() / 2f) - (s.getHeight() / 16f), s.getPaint());
			} else {
				rect.left = (int)(dx - (clicked.getWidth() / 2f));
				rect.top = (int)(dy - (clicked.getHeight() / 2f));
				rect.right = (int)(dx + (clicked.getWidth() / 2f));
				rect.bottom = (int)(dy + (clicked.getHeight() / 2f));
				canvas.drawBitmap(clicked.getClicked(), null, rect, paint);
				canvas.drawText("" + l.getLetter(), dx, dy + (bounds.height() / 2f) + (l.getHeight() / 16f), paint);
			}
		}
		
		invalidate();
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		dx = event.getX();
		dy = event.getY();
		
		for (int i = 0; i < dialogs.size(); i++) {
			if (dialogs.get(i).isVisible()) {
				dialogs.get(i).onClick(event, dx, dy);
				return true;
			}
		}
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			int i = 0;
			boolean found = false;
			while (!found && i < sprites.size()) {
				if (sprites.get(i).isColliding(dx, dy))
					found = true;
				else
					i++;
			}
			if (found) {
				if (sprites.get(i) instanceof Letter) {
					paint.getTextBounds("" + ((Letter)sprites.get(i)).getLetter(), 0, 1, bounds);
					for (int j = 0; j < shadows.size(); j++)
						shadows.get(j).setHighlighted(true);
				}
				clicked = sprites.get(i);
				clicked.onClick(event, dx, dy);
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (clicked == null)
				return true;
			clicked.onClick(event, dx, dy);
			break;
		case MotionEvent.ACTION_UP:
			if (clicked == null)
				return true;
			
			if (clicked instanceof Letter)
				for (int j = 0; j < shadows.size(); j++)
					shadows.get(j).setHighlighted(false);
			
			clicked.onClick(event, dx, dy);
			clicked = null;
			break;
		}
		return true;
	}
	
	public void onDestroy() {
		for (int i = 0; i < sprites.size(); i++)
			sprites.get(i).onDestroy();
	}
	
	public void prepare() {
		letters.clear();
		shadows.clear();
		buttons.clear();
		sprites.clear();
		createDialogs();
		createButtons();
		if (level < levels.size()) {
			movie = levels.get(level).getMovie();
			createLetters();
			createShadows();
		} else {
			//TODO if all levels completed
		}
	}
	
	public void createLetters()	{
		String temp = movie.replace(" ", "").toUpperCase(Locale.ENGLISH);
		boolean[] indexes = { false, false, false, false, false, false, false, false, false, false, false, false, false, false };
		float scale = WIDTH / 8f;
		for (int i = 0; i < 14; i++) {
			int index = (int)(Math.random() * 14);
			while (indexes[index])
				index = (int)(Math.random() * 14);
			indexes[index] = true;

			boolean key = i < temp.length();
			int n = index % 7;
			int m = (index / 7) + 1;
			float x = (WIDTH / 2) - (scale / 2) - ((n - 3) * scale) - ((n - 3) * (WIDTH / 100));
			float y = HEIGHT - (m * scale) - (m * HEIGHT / 100);
			
			char c =  (key ? temp.charAt(i) : getCharacter());
			/*int idc = getResources().getIdentifier(c + "_clicked", "drawable", activity.getPackageName());
			int idu = getResources().getIdentifier(c + "_unclicked", "drawable", activity.getPackageName());
			Bitmap clicked = BitmapFactory.decodeResource(getResources(), idc);
			Bitmap unclicked = BitmapFactory.decodeResource(getResources(), idu);*/
			
			Letter l = new Letter(shadows, letter_clicked, letter_unclicked, x, y, scale, scale, key, c);
			letters.add(l);
			sprites.add(l);
		}
	}
	
	public void createShadows() {
		ArrayList<String> lines = new ArrayList<String>();
		String[] words = movie.split(" ");
		String line = "";
				
		for (int i = 0; i < words.length; i++) {
			if (line.length() + words[i].length() + 1 > 10) {
				lines.add(new String(line));
				line = words[i];
			} else {
				line += (line.length() == 0 ? "" : " ") + words[i];
			}
		}
		lines.add(new String(line));
				
		float scale = WIDTH / 12f;
		for (int i = 0; i < lines.size(); i++) {
			String l = lines.get(i);
			float b = (((lines.size() / 2) + ((lines.size() + 1) % 2) - i) * scale);
			float p = (((lines.size() - 1) / 2f) - i) * (WIDTH / 100);
			float y = (HEIGHT / 5 * 3) - b - p;
					
			for (int j = 0; j < l.length(); j++) {
				float half = (l.length() % 2) * (scale / 2);
				float bitmap = (((l.length() / 2) - j - (l.length() % 2 == 0 ? 1 : 0) + ((l.length() + 1) % 2)) * scale);
				float percent = (((l.length() - 1) / 2f) - j) * (WIDTH / 100);
				float x = (WIDTH / 2) - half - bitmap - percent;
				
				Shadow s = new Shadow(shadow_normal, shadow_highlighted, x, y, scale, scale, l.charAt(j) == ' ');
				shadows.add(s);
				sprites.add(s);
			}
		}
	}
	
	public void createButtons() {
		float scale = WIDTH / 2.8125f;
		float x = (WIDTH / 2) - (scale / 2);
		float y = (HEIGHT / 10 * 3) - (scale / 2);
		Play p = new Play(activity, play, play, x, y, scale, scale);
		sprites.add(p);
		buttons.add(p);
		
		scale = WIDTH / 7.5f;
		x = WIDTH - scale;
		y = (HEIGHT / 10 * 3) - (HEIGHT / 200) - scale;
		Help h = new Help(dialogs.get(0), help_clicked, help_unclicked, x, y, scale, scale);
		sprites.add(h);
		buttons.add(h);

		y = (HEIGHT / 10 * 3) + (HEIGHT / 200);
		Coin c = new Coin(coin_clicked, coin_unclicked, x, y, scale, scale);
		sprites.add(c);
		buttons.add(c);
	}
	
	public void createDialogs() {
		float w = WIDTH / 1.40625f;
		float c = GameView.WIDTH / 8.4375f / 2f;
		float x = (WIDTH / 2f) - (w / 2f);
		float y = (HEIGHT / 2f) - (w / 2f) - c;
		dialogs.add(new HelpDialog(activity, dialog_clicked, dialog_unclicked, x, y, w + c, w + c));
	}
	
	public char getCharacter() {
		int n = (int)(Math.random() * 26);
		return alphabet[n];
	}
	
	public void done() {
		String res = "";
		boolean found = false;
		int i = 0;
		
		while (!found && i < sprites.size()) {
			if (!(sprites.get(i) instanceof Shadow)) {
				i++;
				continue;
			}
			
			Shadow s = (Shadow) sprites.get(i);
			if (s.isSpace()) {
				res += " ";
				i++;
				continue;
			}
			
			if (s.getLetter() == null) {
				found = true;
				continue;
			}
			
			res += s.getLetter().getLetter();
			i++;
		}
		
		if (!found) {
			if (movie.toLowerCase(Locale.ENGLISH).equals(res.toLowerCase(Locale.ENGLISH))) {
				level++;
				Editor editor = preferences.edit();
				editor.putInt("level", level);
				editor.commit();
				prepare();
				Log.d("Guess", "Korrekt");
			} else {
				Log.d("Guess", "Forkert");
			}
		}
	}
}